package cn.da.shuai.cool.system.service.service.impl;

import cn.da.shuai.cool.common.expection.CoolServiceException;
import cn.da.shuai.cool.common.util.DESedeUtil;
import cn.da.shuai.cool.mybatis.service.impl.CoolServiceImpl;
import cn.da.shuai.cool.system.model.entity.dept.CoolDeptUser;
import cn.da.shuai.cool.system.model.entity.dept.DeptUserDto;
import cn.da.shuai.cool.system.model.entity.dept.DeptUserVo;
import cn.da.shuai.cool.system.model.entity.dept.UpdateDeptUserVo;
import cn.da.shuai.cool.system.model.entity.role.CoolRole;
import cn.da.shuai.cool.system.model.entity.user.*;
import cn.da.shuai.cool.system.model.enums.role.RoleTypeType;
import cn.da.shuai.cool.system.model.enums.user.UserStatusType;
import cn.da.shuai.cool.system.service.mapper.CoolDeptUserMapper;
import cn.da.shuai.cool.system.service.mapper.CoolUserMapper;
import cn.da.shuai.cool.system.service.service.ICoolRoleService;
import cn.da.shuai.cool.system.service.service.ICoolUserService;
import cn.da.shuai.cool.system.service.util.UserUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.anno.Cached;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.Setter;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统用户表 服务实现类
 * </p>
 *
 * @author 大帅哥
 * @since 2025-01-03
 */
@Service
public class CoolUserServiceImpl extends CoolServiceImpl<CoolUserMapper, CoolUser> implements ICoolUserService {

    private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Setter(onMethod_ = @Autowired)
    private ICoolRoleService roleService;

    @Setter(onMethod_ = @Autowired)
    private CoolDeptUserMapper deptUserMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(SaveUserVo vo) {
        if (vo == null) {
            return false;
        }

        if (existUserNo(vo.getUserNo(), null)) {
            return false;
        }

        CoolUser user = new CoolUser();
        BeanUtils.copyProperties(vo, user);

        // 如果手机号不为空，则进行3des加密
        if (StrUtil.isNotBlank(user.getPhone())) {
            user.setPhone(DESedeUtil.encrypt(user.getPhone()));
        }

        // TODO 设置默认密码，这里使用123456作为示例，实际应用中应该使用更安全的方式
        user.setPassword(passwordEncoder.encode("123456"));
        user.setStatus(UserStatusType.NORMAL);
        user.setCreateBy(UserUtil.getUserId());
        boolean save = save(user);
        if (save && CollectionUtil.isNotEmpty(vo.getDeptList())) {
            Integer userId = user.getId();
            UpdateDeptUserVo updateDeptUserVo = new UpdateDeptUserVo();
            updateDeptUserVo.setUserId(userId);
            updateDeptUserVo.setDeptList(vo.getDeptList());
            updateDeptUser(updateDeptUserVo);
        }
        return save;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean update(SaveUserVo vo) {
        if (vo == null || vo.getId() == null) {
            return false;
        }

        if (existUserNo(vo.getUserNo(), vo.getId())) {
            return false;
        }

        // 如果手机号不为空，则进行3des加密
        if (StrUtil.isNotBlank(vo.getPhone())) {
            vo.setPhone(DESedeUtil.encrypt(vo.getPhone()));
        }

        vo.setUpdateBy(UserUtil.getUserId());
        return updateByVo(vo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPassword(Integer id) {
        Integer userId = UserUtil.getUserId();
        // 判断当前用户是否为管理员，只有管理员能重置密码
        List<CoolRole> roles = roleService.getRoleByUserId(userId);
        if (CollectionUtil.isEmpty(roles)) {
            return false;
        }
        CoolRole coolRole = roles.stream()
                .filter(r -> RoleTypeType.SUPER_ROLE.equals(r.getRoleType()))
                .findFirst()
                .orElse(null);
        if (coolRole == null) {
            return false;
        }

        if (!exists(id)) {
            return false;
        }
        CoolUser user = new CoolUser();
        // todo 设置默认密码，这里使用123456作为示例，实际应用中应该使用更安全的方式
        user.setPassword(passwordEncoder.encode("123456"));
        user.setId(id);
        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeStatus(Integer id, UserStatusType status) {
        CoolUser user = getById(id);
        if (user != null) {
            user.setStatus(status);
            return updateById(user);
        }
        return false;
    }

    @Cached(name = "cool:system:user:userDetails", key = "#username", expire = 10, timeUnit = TimeUnit.MINUTES)
    @Override
    public CoolUser getByUsername(String username) {
        if (StrUtil.isBlank(username)) {
            return null;
        }
        LambdaQueryWrapper<CoolUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CoolUser::getUsername, username)
                .eq(CoolUser::getStatus, UserStatusType.NORMAL.getValue());
        return this.getOne(wrapper);
    }

    @Override
    public List<String> getMenuPermsById(Integer id) {
        if (id == null) {
            return List.of();
        }
        return baseMapper.selectMenuPerms(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modifyPassword(ModifyPasswordVo vo) {

        // TODO 限制修改密码的频率，例如限制在10分钟内只能修改一次

        if (vo == null) {
            return false;
        }
        String oldPassword = vo.oldPassword();
        String newPassword = vo.newPassword();
        Integer userId = UserUtil.getUserId();
        if (StrUtil.isBlank(oldPassword) || StrUtil.isBlank(newPassword) || userId == null) {
            return false;
        }

        if (oldPassword.equals(newPassword)) {
            return false;
        }

        // 查询用户信息
        PasswordDto passwordDto = this.oneById(userId, PasswordDto.class);
        if (passwordDto == null) {
            return false;
        }

        // 验证旧密码是否正确
        if (!passwordEncoder.matches(oldPassword, passwordDto.getPassword())) {
            return false;
        }

        // 更新密码
        CoolUser user = new CoolUser();
        user.setId(userId);
        user.setPassword(passwordEncoder.encode(newPassword));
        return updateById(user);
    }

    @Override
    public List<Integer> getUserIdsByRole(Integer userId) {
        if (userId == null) {
            return List.of();
        }
        return this.baseMapper.selectUserIdsByRole(userId);
    }

    @Override
    public List<Integer> getUserIdsByPosition(Integer userId) {
        if (userId == null) {
            return List.of();
        }
        return this.baseMapper.selectUserIdsByPosition(userId);
    }

    @Override
    public List<Integer> getUserIdsByDept(Integer userId) {
        if (userId == null) {
            return List.of();
        }
        return this.baseMapper.selectUserIdsByDept(userId);
    }

    @Override
    public boolean existUserNo(String userNo, Integer id) {
        if (StrUtil.isBlank(userNo)) {
            return false;
        }
        LambdaQueryWrapper<CoolUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(CoolUser::getId);
        wrapper.eq(CoolUser::getUserNo, userNo);
        wrapper.ne(id != null, CoolUser::getId, id);
        return this.exists(wrapper);
    }

    @Override
    public UserDto getDetails(Integer id) {
        if (id == null) {
            return null;
        }
        UserDto one = this.one(id, UserDto.class);
        if (one == null) {
            return null;
        }
        one.setDeptList(getDeptUserList(id));
        if (StrUtil.isNotBlank(one.getPhone())) {
            // 解密手机号
            if (StrUtil.isNotBlank(one.getPhone())) {
                one.setPhone(DESedeUtil.decrypt(one.getPhone()));
            }
        }
        return one;
    }

    @Override
    public List<DeptUserDto> getDeptUserList(Integer userId) {
        if (userId == null) {
            return List.of();
        }
        return deptUserMapper.selectDeptUserByUserId(userId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateIp(Integer userId, String ip) {
        if (userId == null || StrUtil.isBlank(ip)) {
            return false;
        }
        CoolUser user = new CoolUser();
        user.setId(userId);
        user.setLastLoginIp(ip);
        user.setLastLoginTime(LocalDateTime.now());
        return updateById(user);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateDeptUser(UpdateDeptUserVo vo) {
        if (vo == null) {
            return false;
        }

        if (CollectionUtil.isNotEmpty(vo.getDeptList())) {
            long count = vo.getDeptList().stream()
                    .filter(deptUserVo -> deptUserVo.isMain() !=null && deptUserVo.isMain() == 1).count();
            if (count != 1) {
                throw new CoolServiceException(400, "必须且只能设置一个主部门");
            }
        }

        deptUserMapper.delete(new LambdaQueryWrapper<CoolDeptUser>().eq(CoolDeptUser::getUserId, vo.getUserId()));
        List<DeptUserVo> deptList = vo.getDeptList();
        if (CollectionUtil.isEmpty(deptList)) {
            return true;
        }
        Integer userId = UserUtil.getUserId();
        List<CoolDeptUser> deptUsers = deptList.stream().map(deptUserVo -> {
            CoolDeptUser deptUser = BeanUtil.toBean(deptUserVo, CoolDeptUser.class);
            deptUser.setCreateBy(userId);
            return deptUser;
        }).collect(Collectors.toList());

        deptUserMapper.insert(deptUsers);
        return true;
    }

    @Override
    public List<UserListDto> getUserList(SearchUserVo vo) {
        if (vo == null) {
            return List.of();
        }
        return baseMapper.selectUserList(vo);
    }

}
